using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TallComponents.Web.Pdf.Resources;

[assembly: WebResource(TallComponents.Web.Pdf.PdfThumbnailsList.ScriptResourcePath, "text/javascript")]
[assembly: WebResource(TallComponents.Web.Pdf.PdfThumbnailsList.EmptyPageImagePath, "image/png")]
[assembly: WebResource(TallComponents.Web.Pdf.PdfThumbnailsList.BlankImagePath, "image/x-win-bitmap")]

namespace TallComponents.Web.Pdf
{
   /// <summary>
   /// Renders a list of thumbnails.
   /// </summary>
   [System.Drawing.ToolboxBitmap(typeof(PdfThumbnailsList), IconPath)]
   [ToolboxItem("System.Web.UI.Design.WebControlToolboxItem, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
   public class PdfThumbnailsList : ScriptControl
   {
      /// <summary>
      /// Initializes a new instance of the <see cref="PdfThumbnailsList"/> class.
      /// </summary>
      public PdfThumbnailsList()
      {
         Orientation = Orientation.Vertical;
      }

      internal const string IconPath = "TallComponents.Web.Pdf.PdfWebViewer.ico";
      internal const string BlankImagePath = "TallComponents.Web.Pdf.white.png";

      // This is the resource path to the javascript source file
      // Note that resource paths always start with the assembly default namespace
#if DEBUG
      internal const string ScriptResourcePath = "TallComponents.Web.Pdf.PdfThumbnailsList.js";
#else
      internal const string ScriptResourcePath = "TallComponents.Web.Pdf.PdfThumbnailsList.min.js";
#endif

      internal const string ClientControlType = "TallComponents.ThumbnailsList";

      internal const string EmptyPageImagePath = "TallComponents.Web.Pdf.white.png";

      /// <summary>
      /// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
      /// </summary>
      /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
      protected override void OnPreRender(EventArgs e)
      {
         base.OnPreRender(e);

         if (string.IsNullOrEmpty(PdfViewerControlId))
            throw new InvalidOperationException(Text.PdfViewerControlId_not_set);

         var targetControl = FindTargetControl(PdfViewerControlId) as PdfViewer;

         if (null == targetControl)
            throw new InvalidOperationException(string.Format(Text.ViewerControl_not_found, PdfViewerControlId));

         _pageViewChildControlId = targetControl.ClientID;

         _storageKey = targetControl.StorageKey;
         _storageProviderName = targetControl.StorageProviderName;

         if (string.IsNullOrEmpty(ServiceUrl))
            throw new HttpException(Text.Thumbnails_ServiceUrl_not_set);

         var listStyle = new CssStyle();
         listStyle.Add("margin", "0px");
         listStyle.Add("padding", "0px");
         //listStyle.Add( "height", "inherit" );
         if (Orientation == Orientation.Horizontal)
            listStyle.Add("white-space", "nowrap");
         Page.Header.StyleSheet.CreateStyleRule(listStyle, this, string.Format("#{0} ul", ClientID));

         var listItemStyle = new CssStyle();
         listItemStyle.Add("margin", "0px");
         listItemStyle.Add("padding", "0px");
         listItemStyle.Add("list-style-position", "outside");
         listItemStyle.Add("list-style-type", "none");
         if (Orientation == Orientation.Horizontal)
         {
            // browser dependent styles...
            bool inlineBlockNotSupported =
               (Context.Request.Browser.Browser.Equals("IE") && (Context.Request.Browser.MajorVersion < 8)) ||
               (Context.Request.Browser.Browser.Equals("Firefox") && (Context.Request.Browser.MajorVersion < 3));

            // display:inline causes IE8 to slow down. inline-block is supported on all new browsers.
            listItemStyle.Add("display", inlineBlockNotSupported ? "inline" : "inline-block");
         }

         Page.Header.StyleSheet.CreateStyleRule(listItemStyle, this, string.Format("#{0} li", ClientID));
      }

      /// <summary>
      /// Renders the control to the specified HTML writer.
      /// </summary>
      /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the control content.</param>
      protected override void Render(HtmlTextWriter writer)
      {
         AddAttributesToRender(writer);
         writer.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "auto");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Position, "relative");
         writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, "center");
         writer.AddStyleAttribute(HtmlTextWriterStyle.OverflowX, Orientation == Orientation.Horizontal ? "scroll" : "hidden");
         writer.AddStyleAttribute(HtmlTextWriterStyle.OverflowY, Orientation == Orientation.Vertical ? "scroll" : "hidden");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         string url = HttpUtility.HtmlAttributeEncode(Page.ClientScript.GetWebResourceUrl(typeof(PdfThumbnailsList), BlankImagePath));
         writer.AddAttribute(HtmlTextWriterAttribute.Src, url);
         writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Height, "100%");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Visibility, "hidden");
         
         writer.RenderBeginTag(HtmlTextWriterTag.Img);
         writer.RenderEndTag();

         writer.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "hidden");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Position, "absolute");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Left, "0px");
         writer.AddStyleAttribute(HtmlTextWriterStyle.Top, "0px");
         writer.RenderBeginTag(HtmlTextWriterTag.Div);

         //writer.AddAttribute(HtmlTextWriterAttribute.Id, "thmbimages123qwe456fgh");
         writer.RenderBeginTag(HtmlTextWriterTag.Ul);

         if (!DesignMode)
         {
            if (!string.IsNullOrEmpty(_storageKey))
            {
               Document doc = Storage.GetDocument(_storageKey);
               if (null != doc)
               {
                  int pageIndex = 0;
                  foreach (var page in doc.Pages)
                  {
                     double thumbScale = scale;
                     if (Orientation == Orientation.Horizontal && !Height.IsEmpty && Height.Type == UnitType.Pixel)
                     {
                        thumbScale = Math.Min(scale, (Height.Value - 26) / page.Height);
                     }
                     else if (Orientation == Orientation.Vertical && !Width.IsEmpty && Width.Type == UnitType.Pixel)
                     {
                        thumbScale = Math.Min(scale, (Width.Value - 26) / page.Width);
                     }

                     string title = string.Format(Text.Thumbnails_Page_nr, pageIndex + 1);
                     int width = (int)(page.Width * thumbScale);
                     int height = (int)(page.Height * thumbScale);
                     string imageUrl = HttpUtility.HtmlAttributeEncode(Page.ClientScript.GetWebResourceUrl(typeof(PdfThumbnailsList), EmptyPageImagePath));
                     string onClickScript = string.Format("$find('{0}').set_pageIndex( {1} );return false;", _pageViewChildControlId, pageIndex);

                     RenderThumbnailMarkup(writer,
                        title,
                        width,
                        height,
                        imageUrl,
                        onClickScript);

                     pageIndex++;
                  }
               }
            }
         }

         writer.RenderEndTag(); // ul
         writer.RenderEndTag(); // div
         writer.RenderEndTag(); // div

         if (!DesignMode)
         {
            ScriptManager.RegisterScriptDescriptors(this);
         }
      }

      private void RenderThumbnailMarkup(HtmlTextWriter writer, string title, int width, int height, string imageUrl, string onClick)
      {
         writer.RenderBeginTag(HtmlTextWriterTag.Li);
         if (null != _thumbnailStyle)
            _thumbnailStyle.AddAttributesToRender(writer);

         writer.AddAttribute(HtmlTextWriterAttribute.Href, "#");
         writer.AddAttribute(HtmlTextWriterAttribute.Onclick, onClick);
         writer.RenderBeginTag(HtmlTextWriterTag.A);
         writer.AddAttribute(HtmlTextWriterAttribute.Width, width.ToString());
         writer.AddAttribute(HtmlTextWriterAttribute.Height, height.ToString());
         writer.AddAttribute(HtmlTextWriterAttribute.Title, title);
         writer.AddAttribute(HtmlTextWriterAttribute.Alt, title);
         writer.AddAttribute(HtmlTextWriterAttribute.Src, imageUrl);
         writer.RenderBeginTag(HtmlTextWriterTag.Img);
         writer.RenderEndTag();

         writer.RenderEndTag(); //a
         writer.RenderEndTag(); //li
      }

      /// <summary>
      /// Searches the control hierarchy to locate the named control.
      /// </summary>
      /// <param name="id">The control id of the control to look for.</param>
      /// <returns>The control with the specified <paramref name="id"/> or <c>null</c> if no matching control is found.</returns>
      /// /// <exception cref="ArgumentException">Occures when <paramref name="id"/> is <c>null</c> or empty.</exception>
      protected Control FindTargetControl(string id)
      {
         if (string.IsNullOrEmpty("id"))
            throw new ArgumentException("id");

         Control ctrl = base.FindControl(id);
         Control namingContainer = NamingContainer;

         // Walk up into the control tree to locate the target control
         while ((null == ctrl) && (null != namingContainer))
         {
            ctrl = namingContainer.FindControl(id);
            namingContainer = namingContainer.NamingContainer;
         }

         return ctrl;
      }

      /// <summary>
      /// Gets or sets the URL for the thumbnail generator.
      /// </summary>
      /// <value>The URL for the thumbnail generator.</value>
      [UrlProperty]
      [Editor("System.Web.UI.Design.UrlEditor", typeof(System.Drawing.Design.UITypeEditor))]
      public string ServiceUrl
      {
         get { return _serviceUrl; }
         set { _serviceUrl = value; }
      }

      /// <summary>
      /// Gets or sets the page view control id.
      /// </summary>
      /// <value>The page view control id.</value>
      [IDReferenceProperty(typeof(PdfViewer))]
      public string PdfViewerControlId
      {
         get { return _pageViewControlId; }
         set { _pageViewControlId = value; }
      }

      /// <summary>
      /// Gets the thumbnail style.
      /// </summary>
      /// <value>The thumbnail style.</value>
      private Style ThumbnailStyle
      {
         get
         {
            if (null == _thumbnailStyle)
               _thumbnailStyle = new Style();
            return _thumbnailStyle;
         }
      }

      /// <summary>
      /// Gets or sets the direction of the list; either vertical (default) or horizontal.
      /// </summary>
      /// <value>The orientation for the list.</value>
      public Orientation Orientation { get; set; }

      /// <summary>
      /// Gets or sets the CSS class for the thumbnail that corresponds to the active page
      /// in the associated PdfViewer.
      /// </summary>
      /// <value>The thumbnail active CSS class.</value>
      public string SelectedThumbnailCssClass { get; set; }

      /// <summary>
      /// Gets or sets the CSS class applied to all thumbnails.
      /// </summary>
      /// <value>The thumbnail CSS class.</value>
      public string ThumbnailCssClass
      {
         get { return ThumbnailStyle.CssClass; }
         set { ThumbnailStyle.CssClass = value; }
      }

      /// <summary>
      /// Gets the script manager for the current request.
      /// </summary>
      /// <value>The script manager for the current request.</value>
      private ScriptManager ScriptManager
      {
         get
         {
            if (_scriptManager == null)
            {
               if (Page == null)
               {
                  throw new InvalidOperationException(Text.Common_PageCannotBeNull);
               }
               _scriptManager = ScriptManager.GetCurrent(Page);
               if (_scriptManager == null)
               {
                  throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Text.Common_ScriptManagerRequired, ID));
               }
            }
            return _scriptManager;
         }
      }

      /// <summary>
      /// Gets the PDF storage.
      /// </summary>
      /// <value>The PDF storage.</value>
      private TallComponents.Web.Storage.IPdfStorage Storage
      {
         get
         {
            if (_storage == null)
            {
               if (_storageProviderName == null)
                  _storage = TallComponents.Web.Storage.PdfStorage.Provider;
               else
                  _storage = TallComponents.Web.Storage.PdfStorage.Providers[_storageProviderName];
            }
            return _storage;
         }
      }

      /// <summary>
      /// Returns the <see cref="T:System.Web.UI.ScriptDescriptor"/> objects for the control.
      /// </summary>
      /// <returns>
      /// An <see cref="T:System.Collections.IEnumerable"/> collection of <see cref="T:System.Web.UI.ScriptDescriptor"/> objects.
      /// </returns>
      protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
      {
         var desc = new ScriptControlDescriptor(ClientControlType, ClientID);
         string url = PdfToImageHandler.GetThumbnailTemplateUrl(ServiceUrl);
         desc.AddProperty("autoScaleMode", Orientation.ToString().ToLower());
         desc.AddProperty("baseUrl", url);
         desc.AddProperty("scale", scale);
         desc.AddProperty("targetControlId", _pageViewChildControlId);
         if (!string.IsNullOrEmpty(ThumbnailCssClass))
            desc.AddProperty("activeCssClass", SelectedThumbnailCssClass);
         desc.AddProperty("storageProviderName", _storageProviderName);
         yield return desc;
      }

      /// <summary>
      /// Returns the script files for the control.
      /// </summary>
      /// <returns>
      /// An <see cref="T:System.Collections.IEnumerable"/> collection that contains ECMAScript (JavaScript) files that have been registered as embedded resources.
      /// </returns>
      protected override IEnumerable<ScriptReference> GetScriptReferences()
      {
         var scriptReferences = new List<ScriptReference> {
            new ScriptReference( ScriptResourcePath, "TallComponents.Web.PdfViewer" )
         };
         return scriptReferences;
      }

      private TallComponents.Web.Storage.IPdfStorage _storage;
      private ScriptManager _scriptManager;

      Style _thumbnailStyle;
      string _pageViewControlId;
      string _pageViewChildControlId;
      string _storageKey;
      string _storageProviderName;
      double scale = 0.25;
      string _serviceUrl = null;
   }
}
